;************************************************************************
;    FIFO BUFFERS FOR CP/M BIOS
;
; The following code is submitted by Glenn Ewing and Bob Richardson
; of MicroPro.  It is intended as an aid to those who wish to implement
; interrupts in their systems.    Also included in the submission is a
; sample port driver and console bios routine intended to show the
; implementation of the routines as ring buffers for a Bios.
;
;  Further Distribution of this file should contain the notice:
;         This code Copyright (c) 1981 MicroPro International Corp.
;			made available by permission of the authors
;			and by MicroPro. Not to be Resold. 
;     Good Luck!  
;		ps: most of this code is Glenn's - Bob R.
.z80
size0	equ	16	; size definition for the fifo queue -must be power of 
;			  2 - actual size depends on the device in questionc
;
;	fifo stuf
	defb	'COPYRIGHT (c) 1981 MicroPro International Corp'  
;
;
;	This module impliments first-in-first-out buffers for the
;	various BIOS I/O paths.  The buffers function as follows:
;
;	If:
;		cnt = number of characters currently stored in buffer, and
;
;		nout = relative position in buffer of characer to be output
;		          next, and
;
;		size = size of buffer (even power of 2), and
;
;		base = address of bottom of buffer, then
;
;	A character is stored in the buffer at address:
;
;		base + ((cnt + nout) mod size)
;
;	and the variables are updated:
;
;		cnt = (cnt + 1) mod size
;
;	Alternately, a character is retrieved from address:
;
;		base + nout
;
;	and the variables are updated:
;
;		cnt = (cnt - 1) mod size
;
;		nout = (nout + 1) mod size.
;
;
;	These items are stored in memory as follows:
;
fifo	macro	size
;
	defb	0		; cnt
	defb	0		; nout
	defb	size-1		; mask for mod ops
	defs	size		; actual buffer
	endm
;
;
;
;	The fifo input and output routines provide no protection
;	from underflow and overflow.  The calling code must use
;	the fstat routine to ensure that these conditions are
;	avoided.  Also, the calling code must enable and disable
;	interupts as appropriate to ensure proper maintainance of
;	the variables.
;
;
fstat:
;	routine to determine status (fullness) of a buffer.
;	enter with ix = adr of cnt.
;	return Z-flag set if buffer empty, Cy set if buffer full.
;	note that buffer capacity is actually size-1.
;
	ld	a, (ix + 0)		; get cnt
	push	de
	ld	e, (ix + 2)		; get mask
	and	e			; cnt = cnt mod size
	dec	e			; e = size - 2
	cp	e			; test for full
	pop	de
	inc	a			; clear z leaving cy
	dec	a
	ccf
	ret
;
;
fin:
;	routine to enter a character into a buffer.
;	enter with c=chr, ix=.cnt
;
	ld	a, (ix + 0)		; compute: (cnt + nout) mod size
	inc	(ix + 0)		; first update cnt
	add	a, (ix + 1)
	and	(ix + 2)
	push	de
	ld	e, a			; compute base + nin
	ld	d, 0
	inc	ix
	inc	ix
	inc	ix
	add	ix, de
	pop	de
	ld	(ix+0), c		; store character
	ret
;
;
;
fout:
;	routine to retreve a character from a buffer.
;	enter with ix=.cnt
;	return with c=chr
;
	dec	(ix + 0)		; update cnt
	ld	a, (ix + 1)		; compute: base + nout
	inc	(ix + 1)
	and	(ix + 2)
	push	de
	ld	e, a
	ld	d, 0
	inc	ix
	inc	ix
	inc	ix
	add	ix, de
	pop	de
	ld	c, (ix + 0)		; get chr
	ret
;
fifo0:	fifo	size0			;  sample invocation of the fifo macro
fifo1:	fifo	size0			; dummy queues for sample codes 
;
sample:
	jp	cboot			; phoney jp
	jp	wboot			; phoney jp
	jp	const			; console status
	jp	conin			; console input vector
	jp	conout			; console output routine
; end of phoney bios branch vector-
; note that for this end of the queueing, all that is necessary is to test
; the status of the queue and return a value based on the queue status-
; not the status of the device-
;
;*************************************************************************
; start of the front end queue - dequeue routines - these routines are
; code samples only and are not intended to run on any particular machine
; and in fact ignore specifically some details of implementation
const:
	ld	ix,fifo0		; note on real sys, you must save ix
;					  this sets up the pointer for the 
;					  fifo routines
	call	fstat			; check on the status of the queue
	ret	z			; return if z-flag set, and hence
;					; no char is ready - this will
;					; also have zero in a at this point
	ld	a,0ffh			; get flag to show that a char is rdy
	ret				; and return that value -
;
;
conin:					; read a char from the queue
	call	const			; first, wait until a char is
					; available - necessary to avoid 
					; underflow
	jp	z,conin			; loop until char is ready
	di				; interrupts must be off to use
					; fin and fout routines
	call	fout			; get a character from the queue
	ld	a,c 			; and put it in correct register
	and	07fh			; strip parity per spec
	ret				; to caller
;
;
conout:					; send a character to the console
	ld	ix,fifo1		; setup for console output queue
	call	fstat			; test queue status
	jp	c,conout		; wait for a space in the queue
					; note: carry set if queue is full
	di				; interrupts off for queue manipulation
	push	ix			; save queue pointer for conditional
					; output routine 
	call	fin			; put a character into the fifo queue
	pop	ix			; restore pointer
	call	tryout 			; routine to output a character and
					; turn on interrupts from console
					; if a character is waiting and if
					; port is not busy
	ei				; restart interrupts
	ret				; to caller

tryout:
;     This routine is installation dependant-
;     it must output a character to the console if and only if
;     the port is ready to accept a character
;     I will not supply the routine, but rather the logic for the routine
;     which would run as follows:
;         select the status port for the console or modem
;	  test the tx ready bit
;	  return if not ready
;	  otherwise if tx is ready to go
;	  call	fout <- gets next char in c register
;  	  output the character to the data port
;	  then return
;*****************************************************************************
;*****************************************************************************
;  now - the easy part - servicing the interrupts from the console/printer/
;  whatever you have hooked up - I am going to just give you the logic for
; the routine we have been working on, without getting into details as this
; is obviously a highly installation dependant part of the code.
;        the philosophy of the coding is, however, the same as the front end
;   when the device needs a character, get one from the queue with
;	   call  fout 			; and then 
;   send the character to the device through whatever mode you use to speak
;   to it - if the queue becomes empty, you generally want to ignore the next
;   interrupt
;  ++++++++++++++++++++++++++++++++++++++++++++
;   if, therefore
;   it is an input device with a character ready
;   read the character from the device and then
;   use
;	   call  fin		; to put the newly read character into  queue
;  if the input queue fills up, you will want to ignore further characters-
;  one standard thing to do is just throw them into the bit bucket and return
;  from the interrupt
;  sample code for the output interrupt on an sio might read:
sint0:
	ld	ix,fifo1	; get output queue
	call	fstat		; check queue status
;
	jp	z,underf	; the queue is empty - no more chars to send
	call	tryout		; note: this is the same routine we created
				; prviously to handle output to port if not
				; busy -
;  This is interrupt code so it is not necessary to disable the interrupts
;  before calling the fin and fout routines
underf:
;this routine should turn off the transmit interrupt with a device dependant
; code - ie, for the sio it would send a 28h to the status port for the sio
; and then
	ret
;the code for an input interrupt would be similar, except the routine would
; read a byte from the device
; call fstat
; ret  c	; throw away character if queue full
; call fin	; else put it in queue
; ret		; and return
;
;
;
;
;******************************************************************************
; the end - note - this file is copyright (c) Micropro International Corp.
; and may not be duplicated in whole or in part for resale. The code
; contained here does not exist in any real implementation of bios except for
; the fifo routines and are presented here as a service and in expression
; of our support for this group.  Any source copy of the fifo stuff must
; retain the credits for this piece of code.  Good luck, may all your 
; interruptions be quick ones.
;                             -bob-
